import fs from "fs";
import path from "path";
import yaml from "js-yaml";
import inquirer from "inquirer";
import xlsx from "xlsx";
import invert from "lodash/invert.js";
import querystring from "querystring";
import iconv from "iconv-lite";
import dayjs from "dayjs";
import os from "os";
import childProcess from "child_process";

const { spawnSync } = childProcess;

export function sleep(second) {
  return new Promise((resolve) => {
    setTimeout(resolve, 1000 * second);
  });
}

export function jsonToURLString(obj) {
  const params = new URLSearchParams();
  for (let [key, value] of Object.entries(obj)) {
    params.append(key, value);
  }
  return params.toString();
}

export function jsonToGBKURLString(obj) {
  return querystring
    .stringify(obj, null, null, {
      encodeURIComponent: gbkEncodeURIComponent,
    })
    .replace(/'/g, "%27")
    .replace(/%C3%97/g, "%A1%C1"); // x转换成gbk乱码问题
}

function gbkEncodeURIComponent(str) {
  const chinese = new RegExp(/[^\x00-\xff]/g);
  let gbkBuffer = null;
  let i = 0;
  let tempStr = "";
  if (chinese.test(str)) {
    gbkBuffer = iconv.encode(str, "gbk");
    for (i; i < gbkBuffer.length; i++) {
      tempStr += "%" + gbkBuffer[i].toString(16);
    }
    tempStr = tempStr.toUpperCase();
    return tempStr;
  } else {
    return querystring.escape(str);
  }
}

export function setUndefinedValueToEmptyString(obj) {
  const _obj = { ...obj };
  for (const key of Object.keys(_obj)) {
    if (_obj[key] === undefined) {
      _obj[key] = "";
    }
  }
  return _obj;
}

export function writeToFile(
  obj,
  { fileName = "xxx", fileType = "txt", filePath = "" } = {}
) {
  try {
    const content = typeof obj === "string" ? obj : JSON.stringify(obj);
    filePath = path.join(path.resolve(), filePath);
    fs.writeFileSync(`${filePath}${fileName}.${fileType}`, content);
  } catch (err) {
    console.error(err);
  }
}

export function getYamlConfig({
  fileName,
  folderPath = "config",
  backTimes = 2,
}) {
  if (!path) throw new Error(`路径${path}不能为空`);
  const configFilePath = getFilePath({ folderPath, backTimes });
  try {
    const config = yaml.load(fs.readFileSync(`${configFilePath}/${fileName}`, "utf8"));
    return config;
  } catch (err) {
    openFolder(configFilePath);
    console.error(`获取配置文件失败，请确定路径[${configFilePath}]下文件[${fileName}]存在`);
    process.exit(1);
  }
}

export function getFilePath({ fileName = "", folderPath = "", backTimes = 2 } = {}) {
  return path.join(
    path.resolve(),
    "../".repeat(backTimes),
    folderPath,
    fileName
  );
}

export async function selectCommunity(users = {}) {
  if (global.community) return global.community;
  if (Object.keys(users)?.length === 0) {
    console.error(`该系统还未配置社区用户`);
    process.exit(1);
  }
  const res = await inquirer.prompt([
    {
      name: "community",
      message: "请选择录入社区",
      type: "list",
      choices: Object.keys(users),
    },
  ]);
  return (global.community = res.community);
}

export async function selectSystem(system = []) {
  if (global.system) return global.system;
  const res = await inquirer.prompt([
    {
      name: "value",
      message: "请选择录入系统",
      type: "list",
      choices: system,
    },
  ]);
  return (global.system = res.value);
}

export async function selectTask(system) {
  if (global.task) return global.task;
  const arr = [
    { name: "南岗中医", value: "chineseMedicine", system: "cloud" },
    { name: "基卫建档", value: "document", system: "panyu_jiwei" },
    { name: "基卫中医", value: "chineseMedicine", system: "panyu_jiwei" },
  ].filter((item) => item.system === system);
  if (arr.length === 0) {
    console.error(`系统${system}没有可选择任务`);
    process.exit(1);
  } else if (arr.length === 1) {
    return arr[0].value;
  }

  const res = await inquirer.prompt([
    {
      name: "value",
      message: "请选择录入任务类型",
      type: "list",
      choices: arr,
    },
  ]);
  return (global.task = res.value);
}

export async function selectExcel() {
  const path = getFilePath({ backTimes: 3 });
  let files = fs.readdirSync(path);

  files = files.filter((item) => /xlsx?$/.test(item));
  if (files.length === 0) {
    console.error(
      `路径${path}找不到excel文件，请确定temp文件夹里有源excel文件`
    );
    openFolder(path);
    process.exit(1);
  } else if (files.length === 1) {
    return files[0];
  }
  const res = await inquirer.prompt([
    {
      name: "excel",
      message: "请选择录入任务类型",
      type: "list",
      choices: files,
    },
  ]);
  return res.excel;
}

export async function deleteFile(path) {
  const stat = await getStat(path);
  stat && fs.unlinkSync(path);
}

export async function confirmContinue(message) {
  try {
    await inquirer.prompt([{ type: "confirm", message, name: "confirm" }]);
  } catch (err) {
    process.exit(1);
  }
}

export function excelToJson(excelName, DICT = {}) {
  const path = getFilePath({ backTimes: 3, fileName: excelName });
  const workbook = xlsx.readFile(path);
  const sheet = workbook.Sheets[workbook.SheetNames[0]];
  const [, lastCell] = sheet["!ref"].split(":");
  const lastColumn = xlsx.utils.decode_cell(lastCell).c;
  for (let i = 0; i <= lastColumn; i++) {
    const titleCellAddress = `${xlsx.utils.encode_col(i)}1`;
    if (!sheet[titleCellAddress]) continue;
    sheet[titleCellAddress].w =
      DICT[sheet[titleCellAddress].w] ?? sheet[titleCellAddress].w;
  }
  const excelData = xlsx.utils.sheet_to_json(sheet, { defval: "" });
  return excelData;
}

export async function jsonToExcel({
  data,
  fileName = dayjs().format("YYYY-MM-DD"),
  DICT,
  folder,
} = {}) {
  folder = folder ?? `${getFilePath({ backTimes: 3 })}/result`;
  const wb = xlsx.utils.book_new();
  const ws = xlsx.utils.json_to_sheet(data, {
    origin: "A2",
    skipHeader: true,
  });
  const heading = Object.keys(data[0]).map((item) => DICT[item] ?? item);
  xlsx.utils.sheet_add_aoa(ws, [heading]);
  xlsx.utils.book_append_sheet(wb, ws);
  await dirExists(folder);
  xlsx.writeFile(wb, `${folder}/${fileName}.xlsx`);
}

export function getInvertDict(dict, dictName) {
  const tempDict = dict[dictName];
  const tempInvertDict = invert(tempDict);
  return { [dictName]: tempDict, [`${dictName}_INVERT`]: tempInvertDict };
}

export function setPersonStatusAndNote(person, STATUS = "", NOTE = "") {
  return { ...person, STATUS, NOTE };
}

export function setStatusAndNote(STATUS = "", NOTE = "") {
  return { STATUS, NOTE };
}

export async function dirExists(dir) {
  let isExists = await getStat(dir);
  // 如果该路径且不是文件，返回true
  if (isExists && isExists.isDirectory()) {
    return true;
  } else if (isExists) {
    // 如果该路径存在但是文件，返回false
    return false;
  }
  // 如果该路径不存在，拿到上级路径
  let tempDir = path.parse(dir).dir;
  // 递归判断，如果上级目录也不存在，则会代码会在此处继续循环执行，直到目录存在
  let status = await dirExists(tempDir);
  let mkdirStatus;
  if (status) {
    mkdirStatus = await mkdir(dir);
  }
  return mkdirStatus;
}

function getStat(path) {
  return new Promise((resolve) => {
    fs.stat(path, (err, stats) => {
      if (err) resolve(false);
      resolve(stats);
    });
  });
}

function mkdir(dir) {
  return new Promise((resolve) => {
    fs.mkdir(dir, (err) => {
      if (err) resolve(false);
      resolve(true);
    });
  });
}

function getPlatform() {
  const platform = os.platform();
  const isMac = platform === "darwin";
  const isWin = platform === "win32";
  return { isMac, isWin };
}

export function openFolder(path) {
  const { isMac } = getPlatform();
  console.log({isMac})
  if (isMac) {
    console.log(path)
    spawnSync("open", [path]);
  } else if (isWin) {
    spawnSync("explorer.exe", [path]);
  }
}
